package com.hmkj.web.controller.simulation;

import com.hmkj.common.entity.ResultEntity;
import com.hmkj.common.page.BasePageParams;
import com.hmkj.common.page.Pages;
import com.hmkj.common.utils.*;
import com.hmkj.core.api.juhe.bean.epay.base.DateTimeHelper;
import com.hmkj.core.constant.ConfigNID;
import com.hmkj.core.eolinker.endpoints.QuotationEndpoint;
import com.hmkj.core.eolinker.models.ModelRealTime;
import com.hmkj.core.exception.BussinessException;
import com.hmkj.core.mapper.simulation.OrderSimulationMapper;
import com.hmkj.core.model.index.OrderSimulationModel;
import com.hmkj.core.model.order.OrderModel;
import com.hmkj.core.po.account.AccountSimulation;
import com.hmkj.core.po.order.Order;
import com.hmkj.core.po.simulation.OrderSimulation;
import com.hmkj.core.po.simulation.Subscribe;
import com.hmkj.core.po.user.User;
import com.hmkj.core.service.simulation.OrderSimulationService;
import com.hmkj.core.service.simulation.SubscribeService;
import com.hmkj.web.controller.GenericController;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * ......................我佛慈悲......................
 * ......................_oo0oo_.......................
 * .....................o8888888o......................
 * .....................88" . "88......................
 * .....................(| -_- |)......................
 * .....................0\  =  /0......................
 * ...................___/`---'\___....................
 * ..................' \\|     |// '...................
 * ................/ \\|||  :  |||// \.................
 * .............../ _||||| -卍-|||||- \................
 * ..............|   | \\\  -  /// |   |...............
 * ..............| \_|  ''\---/''  |_/ |...............
 * ..............\  .-\__  '-'  ___/-. /...............
 * ............___'. .'  /--.--\  `. .'___.............
 * .........."" '<  `.___\_<|>_/___.' >' ""............
 * ........| | :  `- \`.;`\ _ /`;.`/ - ` : | |.........
 * ........\  \ `_.   \_ __\ /__ _/   .-` /  /.........
 * ....=====`-.____`.___ \_____/___.-`___.-'=====......
 * ......................`=---='.......................
 * ....................................................
 * .................佛祖开光 ,永无BUG...................
 */
@Api(description = "模拟点卖")
@Slf4j
@RestController
@RequestMapping(GenericController.MEMBER_URL + "/simulation/sell")
public class AppSellSimulationController extends GenericController<Integer, AccountSimulation> {

    @Resource
    private OrderSimulationService orderSimulationService;
    @Resource
    private SubscribeService subscribeService;

    @ApiOperation(value = "模拟点卖列表", notes = "模拟点卖列表")
    @RequestMapping(value = "/sellList", method = RequestMethod.POST)
    @ResponseBody
    public ResultEntity sellList(@ApiParam("类型  2(持仓) 3(结算)") @RequestParam(required = true) Integer type,
                                 @ModelAttribute BasePageParams basePageParams) throws Exception {
        User user = getLoginUser();
        if (null == type) {
            throw new Exception("请输入类型");
        }
        Map<String, Object> param = new HashMap<>();
        param.put("userId", user.getId());
        if (2 == type) {
            param.put("status", Order.STATUS.T3.code);
        }
        if (3 == type) {
            param.put("status", Order.STATUS.T7.code);
        }
        param.put("basePageParams", basePageParams);
        Pages<OrderSimulationModel> pages = orderSimulationService.selectByPage(basePageParams,
                q -> ((OrderSimulationMapper) q).findCountForOrderSimulation(param),
                q -> ((OrderSimulationMapper) q).findListForOrderSimulation(param));
        List<OrderSimulationModel> orderList = pages.getRows();
        if (CollectionUtils.isNotEmpty(orderList)) {
            for (OrderSimulationModel order : orderList) {
                ModelRealTime realTime = QuotationEndpoint.realtime(order.getEquityCode());
                String lastPrice = realTime.getLast_price();
                order.setLastPrice(lastPrice);
                BigDecimal buyDealPrice = order.getBuyPrice();
                BigDecimal dealNumber = BigDecimal.valueOf(order.getBuyDealNumber());
                //盈亏
                String profit = String.valueOf(BigDecimalUtils.mul(BigDecimalUtils.sub(Double.parseDouble(lastPrice), buyDealPrice.doubleValue()), dealNumber.doubleValue()));
                order.setProfit(profit);
                //判断是否是当日的订单
                OrderSimulation o = orderSimulationService.selectByPrimaryKey(order.getId());
                if (DateUtils.secondBetween(DateUtils.getTodayZero(), o.getBuyTime()) > 0) {
                    //当天订单，不能点卖
                    order.setStatus(9);
                }
                order.setStopLossLine(PriceHelper.format(order.getStopLossLine(), 0));
            }
        }

        //计算持仓盈亏
        double total = 0;
        List<OrderSimulation> orders = orderSimulationService.select(new OrderSimulation(t -> {
            t.setUserId(user.getId());
            t.setStatus(OrderSimulation.STATUS.T3.code);
        }));
        if (CollectionUtils.isNotEmpty(orders)) {
            for (OrderSimulation order : orders) {
                ModelRealTime realTime = QuotationEndpoint.realtime(order.getEquityCode());
                String lastPrice = realTime.getLast_price();
                BigDecimal buyDealPrice = order.getBuyDealPrice();
                BigDecimal dealNumber = BigDecimal.valueOf(order.getBuyDealNumber());
                //盈亏
                String profit = String.valueOf(BigDecimalUtil.mul(BigDecimalUtil.sub(Double.parseDouble(lastPrice), buyDealPrice.doubleValue()), dealNumber.doubleValue()));
                total = total + Double.parseDouble(profit);
            }
        }
        pages.setRows(orderList);
        double finalTotal = total;
        return ok(m -> {
            m.put("data", pages);
            m.put("totalProfit", finalTotal);
        });
    }

    @ApiOperation(value = "模拟结算列表", notes = "模拟结算列表")
    @RequestMapping(value = "/balanceJson", method = RequestMethod.POST)
    @ResponseBody
    public ResultEntity banlanceList(@ApiParam("时间段 近7天（1），近一个月（2），近3个月（3），近一年（4）") @RequestParam(required = true) String date,
                                     @ApiParam("状态 7已结算 8 已流单") @RequestParam(required = false) String status,
                                     @ModelAttribute BasePageParams basePageParams) {
        HashMap<String, Object> param = new HashMap<>();
        User user = getLoginUser();
        param.put("userId", user.getId());
        param.put("date", date);
        //结算、流单
        if (StringUtils.isBlank(status)) {
            status = OrderSimulation.STATUS.T7.code + "," + OrderSimulation.STATUS.T8.code;
        }
        param.put("status", status);
        Pages<OrderSimulationModel> pages = orderSimulationService.selectByPage(basePageParams,
                q -> ((OrderSimulationMapper) q).findBalanceCountForOrderSimulation(param),
                q -> ((OrderSimulationMapper) q).findBalanceForOrderSimulation(param));
        List<OrderSimulationModel> list = pages.getRows();
        if (CollectionUtils.isNotEmpty(list)) {
            for (OrderSimulationModel order : list) {
                //交易分配，盈利总额 * 盈利分配
                if (order.getStatus() == OrderSimulation.STATUS.T7.code) {
                    BigDecimal totalProfit = order.getProfitCount();
                    BigDecimal scale = order.getDivideScale();
                    if (PriceHelper.isLessThan(totalProfit, BigDecimal.ZERO)) {
                        order.setTradeProfit(BigDecimal.ZERO);
                    } else {
                        order.setTradeProfit(BigDecimalUtil.round(String.valueOf(totalProfit.multiply(scale)), 2));
                    }
                }
            }
        }
        pages.setRows(list);
        return ok(pages);
    }

    @ApiOperation(value = "模拟平仓", notes = "模拟平仓")
    @RequestMapping(value = "/toSell", method = RequestMethod.POST)
    @ResponseBody
    public ResultEntity toSell(@ApiParam("订单Id") @RequestParam(required = true) Integer id) throws Exception {
        if (null == id) {
            throw new BussinessException("参数有误");
        }
        OrderSimulation order = orderSimulationService.selectByPrimaryKey(id);
        if (null == order) {
            throw new BussinessException("订单不存在");
        }
        double total = 0;
        //判断是否在交易时段
        Integer isOpenTradeTime = redisService.get(ConfigNID.IS_OPEN_TRADE_TIME,Integer.class);
        if(null == isOpenTradeTime || isOpenTradeTime == 1){
            if(!OrderModel.checkTradeDate()){
                new BussinessException("非交易时间");
            }
        }
        //判断是否是单日的订单
//        if (DateUtils.secondBetween(DateUtils.getTodayZero(), order.getBuyTime()) > 0) {
//            //当天订单，不能点卖
//            throw new BussinessException("当天订单不能平仓");
//        }
        //判断是否是交易中
        if (order.getStatus() != OrderSimulation.STATUS.T3.code) {
            throw new BussinessException("订单状态已更改，请刷新");
        }
        //结算
        ModelRealTime realTime = QuotationEndpoint.realtime(order.getEquityCode());
        orderSimulationService.doOrderSimulateSell(order, realTime.getLast_price());
        return ok("模拟平仓成功",ResultEntity.SUCCESS);
    }

    @ApiOperation(value = "模拟持仓", notes = "模拟持仓")
    @RequestMapping(value = "/hold", method = RequestMethod.POST)
    @ResponseBody
    public ResultEntity hold(@ApiParam("高手Id") @RequestParam(required = true) Integer id,
                             @ModelAttribute BasePageParams basePageParams) throws Exception {
        if (null == id) {
            throw new BussinessException("参数错误");
        }
        Subscribe subscribe = subscribeService.selectByPrimaryKey(id);
        if (subscribe == null) {
            throw new BussinessException("参数错误");
        }

        Map<String, Object> param = new HashMap<>();
        param.put("userId", subscribe.getUserId());
        param.put("status", OrderSimulation.STATUS.T3.code);
        param.put("basePageParams", basePageParams);
        Pages<OrderSimulationModel> pages = orderSimulationService.selectByPage(basePageParams,
                q -> ((OrderSimulationMapper) q).findCountForOrderSimulation(param),
                q -> ((OrderSimulationMapper) q).findListForOrderSimulation(param));
        List<OrderSimulationModel> orderList = pages.getRows();
        if (CollectionUtils.isNotEmpty(orderList)) {
            for (OrderSimulationModel orderSimulation : orderList) {
                //TODO 这个公式有问题  计算止损价格 （点买价格-止损价格）*点买数量 < 止损金额
                //公式  止损价格 = 买入 - |止损线| / 数量
                BigDecimal stopLoss = orderSimulation.getStopLossLine();
                BigDecimal stopPrice = orderSimulation.getBuyPrice().subtract(stopLoss.abs().divide(new BigDecimal(orderSimulation.getBuyDealNumber()), 2));
                orderSimulation.setStopPrice(stopPrice);
                //止盈线
                BigDecimal stopProfitLine = orderSimulation.getStopProfitLine();
                BigDecimal stopProfitPrice = orderSimulation.getBuyPrice().add(stopProfitLine.abs().divide(new BigDecimal(orderSimulation.getBuyDealNumber()), 2));
                orderSimulation.setStopProfitPrice(stopProfitPrice);
                ModelRealTime realTime = QuotationEndpoint.realtime(orderSimulation.getEquityCode());
                if (realTime == null) {
                    realTime = new ModelRealTime();
                }
                orderSimulation.setLastPrice(realTime.getLast_price());
                //浮动盈亏
//                orderSimulation.setCurrentProfit(PriceHelper.format(((new BigDecimal(realTime.getLast_price())).subtract(orderSimulation.getBuyPrice())).divide(orderSimulation.getBuyPrice(), 2)));
                orderSimulation.setCurrentProfit(PriceHelper.format((new BigDecimal(realTime.getLast_price()).subtract(orderSimulation.getBuyPrice())).multiply(new BigDecimal(orderSimulation.getBuyDealNumber())), 2));
                //持仓天数
                orderSimulation.setHoldDay(DateTimeHelper.getDateDaySpace(orderSimulation.getCreateTime(), new Date()));
            }
        }
        return ok(pages);
    }

    @ApiOperation(value = "模拟记录", notes = "模拟记录")
    @RequestMapping(value = "/history", method = RequestMethod.POST)
    @ResponseBody
    public ResultEntity history(@ApiParam("高手Id") @RequestParam(required = true) Integer id,
                                @ModelAttribute BasePageParams basePageParams) throws Exception {
        if (null == id) {
            throw new BussinessException("参数错误");
        }
        Subscribe subscribe = subscribeService.selectByPrimaryKey(id);
        if (subscribe == null) {
            throw new BussinessException("参数错误");
        }

        Map<String, Object> param = new HashMap<>();
        param.put("userId", subscribe.getUserId());
        param.put("status", OrderSimulation.STATUS.T7.code);
        param.put("basePageParams", basePageParams);
        Pages<OrderSimulationModel> pages = orderSimulationService.selectByPage(basePageParams,
                q -> ((OrderSimulationMapper) q).findCountForOrderSimulation(param),
                q -> ((OrderSimulationMapper) q).findListForOrderSimulation(param));
        List<OrderSimulationModel> orderList = pages.getRows();
        if (CollectionUtils.isNotEmpty(orderList)) {
            for (OrderSimulationModel orderSimulation : orderList) {
                //计算止损价格 （点买价格-止损价格）* 点买数量 < 止损金额
                BigDecimal stopLoss = orderSimulation.getStopLossLine();
                BigDecimal stopPrice = orderSimulation.getBuyPrice().subtract(stopLoss.abs().divide(new BigDecimal(orderSimulation.getBuyDealNumber()), 2));
                orderSimulation.setStopPrice(stopPrice);
                //止盈线
                BigDecimal stopProfitLine = orderSimulation.getStopProfitLine();
                BigDecimal stopProfitPrice = orderSimulation.getBuyPrice().add(stopProfitLine.abs().divide(new BigDecimal(orderSimulation.getBuyDealNumber()), 2));
                orderSimulation.setStopProfitPrice(stopProfitPrice);
                ModelRealTime realTime = QuotationEndpoint.realtime(orderSimulation.getEquityCode());
                //浮动盈亏比
//                orderSimulation.setCurrentProfit(PriceHelper.format(((orderSimulation.getSellDealPrice().subtract(orderSimulation.getBuyPrice())).divide(orderSimulation.getBuyPrice(), 2))));
                orderSimulation.setCurrentProfit(PriceHelper.format((orderSimulation.getSellDealPrice().subtract(orderSimulation.getBuyPrice())).multiply(orderSimulation.getTradeCredit().multiply(BigDecimal.valueOf(10000))), 2));

                //持仓天数
                orderSimulation.setHoldDay(DateTimeHelper.getDateDaySpace(orderSimulation.getCreateTime(), orderSimulation.getSettleTime()));
            }
        }
        return ok(pages);
    }

    @ApiOperation(value = "点卖明细", notes = "点卖明细")
    @RequestMapping(value = "/sellDetailJson", method = RequestMethod.POST)
    @ResponseBody
    public ResultEntity sellDetail(@ApiParam("模拟订单Id") @RequestParam(required = true) Integer id) throws Exception {
        if (null == id) {
            throw new BussinessException("参数有误");
        }
        OrderSimulation order = orderSimulationService.selectByPrimaryKey(id);
        if (order == null) {
            throw new BussinessException("订单不存在");
        }
        return ok(order);
    }

    @ApiOperation(value = "结算明细", notes = "结算明细")
    @RequestMapping(value = "/balanceDetailJson", method = RequestMethod.POST)
    @ResponseBody
    public ResultEntity banlanceDetail(@ApiParam("模拟订单Id") @RequestParam(required = true) Integer id) throws Exception {
        if (null == id) {
            throw new BussinessException("参数有误");
        }
        OrderSimulation order = orderSimulationService.selectByPrimaryKey(id);
        if (order == null) {
            throw new BussinessException("订单不存在");
        }
        OrderSimulationModel model = new OrderSimulationModel();
        BeanUtils.copyProperties(order, model);
        if (PriceHelper.isLessThan(order.getProfitCount(), BigDecimal.ZERO)) {
            model.setTradeProfit(BigDecimal.ZERO);
        } else {
            model.setTradeProfit(BigDecimalUtil.round(String.valueOf(order.getProfitCount().multiply(order.getDivideScale())), 2));
        }
        return ok(model);
    }

    @ApiOperation(value = "修改止损", notes = "修改止损")
    @RequestMapping(value = "/alterStopLoss", method = RequestMethod.POST)
    @ResponseBody
    public ResultEntity alterStopLoss(@ApiParam("id") @RequestParam(required = true) Integer id,
                                       @ApiParam("止损价格") @RequestParam(required = true) BigDecimal stopLosePrice,
                                       @ApiParam("需要追加的保证金") @RequestParam(required = true) BigDecimal needDeposit) throws Exception {
        if (null == id) {
            throw new BussinessException("参数有误");
        }
        if (null == stopLosePrice || PriceHelper.isLessThanOrEquals(stopLosePrice, BigDecimal.ZERO)) {
            throw new BussinessException("请填写止损价格");
        }
        if (null == needDeposit || PriceHelper.isLessThan(needDeposit, BigDecimal.ZERO)) {
            throw new BussinessException("需要追加的保证金填写有误");
        }
        OrderSimulation orderSimulation = orderSimulationService.selectByPrimaryKey(id);
        if (null == orderSimulation) {
            throw new BussinessException("订单不存在");
        }
        if (orderSimulation.getStatus() != Order.STATUS.T3.code) {
            throw new BussinessException("订单状态已改变，请刷新");
        }
        ModelRealTime modelRealTime = QuotationEndpoint.realtime(orderSimulation.getEquityCode());
        if (null == modelRealTime) {
            throw new BussinessException("股票信息出错");
        }
        orderSimulationService.doAlterStopLoss(orderSimulation, stopLosePrice,needDeposit,new BigDecimal(modelRealTime.getLast_price()));
        return ok("修改止损成功",ResultEntity.SUCCESS);
    }
}
